package cn.fresh.xuanyuan.module.system.service.wx;

import cn.fresh.xuanyuan.framework.common.enums.UserTypeEnum;
import cn.fresh.xuanyuan.framework.common.pojo.PageParam;
import cn.fresh.xuanyuan.framework.common.pojo.PageResult;
import cn.fresh.xuanyuan.module.system.dal.dataobject.social.SocialClientDO;
import cn.fresh.xuanyuan.module.system.dal.dataobject.wx.TemplateConfigDO;
import cn.fresh.xuanyuan.module.system.dal.dataobject.wx.WXSendLogDO;
import cn.fresh.xuanyuan.module.system.dal.dataobject.wx.WXSubscribeDO;
import cn.fresh.xuanyuan.module.system.dal.mysql.social.SocialClientMapper;
import cn.fresh.xuanyuan.module.system.dal.mysql.social.SocialUserMapper;
import cn.fresh.xuanyuan.module.system.dal.mysql.wx.TemplateConfigMapper;
import cn.fresh.xuanyuan.module.system.dal.mysql.wx.WXSendLogMapper;
import cn.fresh.xuanyuan.module.system.dal.mysql.wx.WXSubscribeMapper;
import cn.fresh.xuanyuan.module.system.enums.social.SocialTypeEnum;
import cn.fresh.xuanyuan.module.system.model.request.SubscribeMessageRequest;
import cn.fresh.xuanyuan.module.system.model.request.TemplateData;
import cn.fresh.xuanyuan.module.system.model.request.WXSendRequest;
import cn.fresh.xuanyuan.module.system.model.request.WXTemplateDataMap;
import cn.fresh.xuanyuan.module.system.util.wx.WXMessageUtil;
import cn.hutool.core.collection.CollectionUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;

import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CountDownLatch;

import static cn.fresh.xuanyuan.module.system.job.config.WXJobConfiguration.WX_MSG_THREAD_POOL_TASK_EXECUTOR;

@Service
@Slf4j
public class WXSubscribeServiceImpl implements WXSubscribeService {

    @Resource
    private TemplateConfigMapper templateConfigMapper;

    @Resource
    private WXSubscribeMapper wxSubscribeMapper;

    @Resource
    private WXSendLogMapper wxSendLogMapper;

    @Resource(name = WX_MSG_THREAD_POOL_TASK_EXECUTOR)
    private ThreadPoolTaskExecutor threadPoolTaskExecutor;

    @Resource
    private SocialUserMapper socialUserMapper;

    @Resource
    private SocialClientMapper socialClientMapper;

    @Override
    public void send(Long sysUserId, WXSendRequest request) {
        TemplateConfigDO templateConfig = templateConfigMapper.selectById(request.getId());
        if(templateConfig != null) {
            threadPoolTaskExecutor.execute(() -> startTask(sysUserId, request, templateConfig));
        }
    }

    private void startTask(Long sysUserId, WXSendRequest request, TemplateConfigDO templateConfig) {
        long total = wxSubscribeMapper.countMember(templateConfig.getTemplateId());
        if(total > 0) {
            WXSendLogDO sendLogDO = WXSendLogDO.builder()
                    .templateId(templateConfig.getTemplateId())
                    .total(0)
                    .status(0)
                    .build();
            sendLogDO.setCreateTime(LocalDateTime.now());
            sendLogDO.setCreator(String.valueOf(sysUserId));
            wxSendLogMapper.insert(sendLogDO);
            if(total > 10) {
                long totalPage = total / 10 + 1;
                for(int i = 0; i < totalPage; i++) {
                    PageParam pageParam = new PageParam();
                    pageParam.setPageNo(i+1);
                    PageResult<WXSubscribeDO> page = wxSubscribeMapper.getList(new PageParam(), templateConfig.getTemplateId());
                    if(page != null && CollectionUtil.isNotEmpty(page.getList())) {
                        taskHandle(page.getList(), request, templateConfig, sendLogDO);
                    }
                }
            }
            else {
                PageResult<WXSubscribeDO> page = wxSubscribeMapper.getList(new PageParam(), templateConfig.getTemplateId());
                if(page != null && CollectionUtil.isNotEmpty(page.getList())) {
                    taskHandle(page.getList(), request, templateConfig, sendLogDO);
                }
            }
        }
    }

    private void taskHandle(List<WXSubscribeDO> list, WXSendRequest request, TemplateConfigDO templateConfig,WXSendLogDO sendLogDO) {
        CountDownLatch latch = new CountDownLatch(list.size());
        list.forEach(wxSubscribeDO -> threadPoolTaskExecutor.execute(() -> {
            try {
                sendMsgHandle(wxSubscribeDO, request, templateConfig);
            }
            finally {
                latch.countDown();
            }
        }));
        // 等待完成
        try {
            latch.await();
        } catch (InterruptedException e) {
            log.error("线程中断");
        }
        WXSendLogDO existLog = wxSendLogMapper.selectById(sendLogDO.getId());
        existLog.setTotal(existLog.getTotal() + list.size());
        existLog.setStatus(1);
        existLog.setUpdateTime(LocalDateTime.now());
        wxSendLogMapper.updateById(existLog);
    }

    private void sendMsgHandle(WXSubscribeDO wxSubscribeDO, WXSendRequest request, TemplateConfigDO templateConfig) {
        String openid = wxSubscribeDO.getOpenId();
        if(StringUtils.isBlank(openid)) {
            openid = socialUserMapper.getMemberOpenId(wxSubscribeDO.getMemberId(), UserTypeEnum.MEMBER.getValue(), SocialTypeEnum.WECHAT_MINI_APP.getType());
        }
        if(StringUtils.isNotBlank(openid)) {
            SocialClientDO socialClientDO = socialClientMapper.getSocialClientDOByAppId(templateConfig.getAppId());
            if(socialClientDO != null && StringUtils.isNotBlank(socialClientDO.getAccessToken())) {
                Map<String, TemplateData> data = new HashMap<>();
                for(WXTemplateDataMap map : request.getData()) {
                    data.put(map.getDataKey(), new TemplateData(map.getValue()));
                }
                SubscribeMessageRequest request1 = new SubscribeMessageRequest();
                request1.setTemplate_id(templateConfig.getTemplateId());
                request1.setTouser(openid);
                if(StringUtils.isNotBlank(request.getPageUrl())) {
                    request1.setPage(request.getPageUrl());
                }
                request1.setData(data);
                WXMessageUtil.sendMessage(request1, socialClientDO.getAccessToken());
            }
        }
    }
}
